/*
 * BigIntegerTests.cpp
 *
 *  Created on: Jul 4, 2010
 *      Author: Lukasz Spintzyk
 */

//#define DBG_NO_CUDA

#include <iostream>
#include <iomanip>

#include <cppunit/TestRunner.h>
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/BriefTestProgressListener.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <iostream>

#include "BigInteger.h"
#include "CudaBNImplementation.h"

class TestBigInteger: public CPPUNIT_NS::TestCase
{
	CPPUNIT_TEST_SUITE(TestBigInteger);
		CPPUNIT_TEST(initBigNumberTest0);
		CPPUNIT_TEST(incrementBigNumber);
		CPPUNIT_TEST(initBigNumberTest1);
		CPPUNIT_TEST(cmpBigIntegerTest);
		CPPUNIT_TEST(addTest);
		CPPUNIT_TEST(BN_addWordTest);
		CPPUNIT_TEST(BN_addWord2Test);
		CPPUNIT_TEST(BN_addWord3Test);
		CPPUNIT_TEST(BN_addWord4Test);
		//CPPUNIT_TEST(cmpBigIntegerTest);
		//CPPUNIT_TEST(cmpBigIntegerTest);


	CPPUNIT_TEST_SUITE_END();

public:
	void setUp(void)
	{
		iv = "9999888877776666111199998888777766661111";
		iv_inc = "9999888877776666111199998888777766661112";
		bin_val = new byte[100];
	}
	void tearDown(void)
	{
		delete[] bin_val;
	}

protected:
	void initBigNumberTest0(void)
	{
		BigInteger a(iv,0);
		CPPUNIT_ASSERT(strcmp(a.c_str() , iv.c_str()) == 0);

		BigInteger b("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",0);
		int len = b.getBinValue(bin_val);
		CPPUNIT_ASSERT(len == 16);
	}

	void initBigNumberTest1(void)
	{
		BigInteger a(iv,0);
		BigInteger b(++a);
		CPPUNIT_ASSERT(strcmp(a.c_str() , iv_inc.c_str()) == 0);
		CPPUNIT_ASSERT(strcmp(b.c_str() , iv_inc.c_str()) == 0);
	}

	void cmpBigIntegerTest(void)
	{
		BigInteger a(iv, 1);
		BigInteger b(iv, 0);
		b++;
		CPPUNIT_ASSERT(a == b);
	}
	void incrementBigNumber()
	{
		BigInteger a(iv,0);
		a++;
		BigInteger b(iv, 0);
		++b;

		CPPUNIT_ASSERT(strcmp(a.c_str() , iv_inc.c_str()) == 0);
		CPPUNIT_ASSERT(strcmp(b.c_str() , iv_inc.c_str()) == 0);
	}

	void addTest()
	{
		BigInteger a(iv, 0);
		BigInteger b(iv, 10);
		a = a +10;
		CPPUNIT_ASSERT(a == b);
		b = b + (-10);
		a = a  + (- 10);
		CPPUNIT_ASSERT(a == b);

	}

	void BN_addWordTest()
	{
		BigInteger a(iv, 2425);
		BigInteger b(iv, 2425);

		for (int i = 13; i < 134561; i+=31)
		{
			a = a +i;
			BN_add_word_ver2(b.value, i);
			CPPUNIT_ASSERT(a == b);
		}

	}

	void BN_addWord2Test()
	{
		BigInteger a(iv, 0);
		BigInteger b(iv, 0);


		for (unsigned long i = 0; i < 1233; i++)
		{
			a = a +i+2148100266;
			BN_add_word(b.value, i+2148100266);
			CPPUNIT_ASSERT(a == b);
		}

	}

	void BN_addWord3Test()
	{
		BigInteger a(0);
		BigInteger b(0);


		for (unsigned long i = 0; i < 1233; i++)
		{
			a = a +i+2148100266;
			BN_add_word(b.value, i+2148100266);
			CPPUNIT_ASSERT(a == b);
		}

	}

	void BN_addWord4Test()
	{
		BigInteger a(0);
		BigInteger b(0);


		for (unsigned long i = 0; i < 1233; i++)
		{
			a = a +i;
			BN_add_word(b.value, i);
			CPPUNIT_ASSERT(a == b);
		}

	}

private:
	std::string iv;
	std::string iv_inc;
	byte* bin_val;

};

CPPUNIT_TEST_SUITE_REGISTRATION(TestBigInteger);

int main(int ac, char **av)
{
	//--- Create the event manager and test controller
	CPPUNIT_NS::TestResult controller;
	//--- Add a listener that colllects test result
	CPPUNIT_NS::TestResultCollector result;
	controller.addListener(&result);
	//--- Add a listener that print dots as test run.
	CPPUNIT_NS::BriefTestProgressListener progress;
	controller.addListener(&progress);
	//--- Add the top suite to the test runner
	CPPUNIT_NS::TestRunner runner;
	runner.addTest(CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest());
	runner.run(controller);

	return result.wasSuccessful() ? 0 : 1;
}
